|
1
|
|
|
var _ = require('lodash'); |
|
2
|
|
|
var blocktrail = require('../'); |
|
3
|
|
|
var q = require('q'); |
|
4
|
|
|
var crypto = require('crypto'); |
|
5
|
|
|
var async = require('async'); |
|
6
|
|
|
var bitcoin = require('bitcoinjs-lib'); |
|
7
|
|
|
var bip39 = require("bip39"); |
|
8
|
|
|
|
|
9
|
|
|
/** |
|
10
|
|
|
* @type APIClient |
|
11
|
|
|
*/ |
|
12
|
|
|
var client = blocktrail.BlocktrailSDK({ |
|
13
|
|
|
apiKey : process.env.BLOCKTRAIL_SDK_APIKEY || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APIKEY", |
|
14
|
|
|
apiSecret : process.env.BLOCKTRAIL_SDK_APISECRET || "EXAMPLE_BLOCKTRAIL_SDK_NODEJS_APISECRET", |
|
15
|
|
|
testnet : true |
|
16
|
|
|
}); |
|
17
|
|
|
|
|
18
|
|
|
// aggregate TXs will try to have N outputs |
|
19
|
|
|
var SPLITNOUTS = 5; |
|
20
|
|
|
// don't go below MINVALUE when trying to send |
|
21
|
|
|
var MINVALUE = 10000; |
|
22
|
|
|
// don't glo below MINSPLITVALUE for outputs (nouts will be rounded down to match this) |
|
23
|
|
|
var MINSPLITVALUE = 10000; |
|
24
|
|
|
var ONEBTC = 1e8; |
|
25
|
|
|
|
|
26
|
|
|
client.initWallet({ |
|
27
|
|
|
identifier: "unittest-transaction", |
|
28
|
|
|
password: "password" |
|
29
|
|
|
}) |
|
30
|
|
|
.then(function(wallet) { |
|
31
|
|
|
// @DBEUG |
|
32
|
|
|
// return wallet.utxos().then(function(utxos) { |
|
33
|
|
|
// console.log(utxos); |
|
34
|
|
|
// }); |
|
35
|
|
|
|
|
36
|
|
|
return wallet.maxSpendable(false).then(function(maxSpendable) { |
|
37
|
|
|
console.log(maxSpendable); |
|
|
|
|
|
|
38
|
|
|
|
|
39
|
|
|
// get the address to aggregate the coins to |
|
40
|
|
|
var addr = wallet.getAddressByPath("M/9999'/0/0"); |
|
41
|
|
|
console.log(addr); |
|
42
|
|
|
|
|
43
|
|
|
var splitSend = function(value) { |
|
44
|
|
|
var pay = []; |
|
45
|
|
|
var splitValue = Math.max(MINSPLITVALUE, Math.floor(value / SPLITNOUTS)).toFixed(0); |
|
46
|
|
|
var nouts = Math.floor(value / splitValue); |
|
47
|
|
|
|
|
48
|
|
|
for (var i = 0; i < nouts; i++) { |
|
49
|
|
|
pay.push({address: addr, value: splitValue}); |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
return wallet.pay(pay, null, false, false, blocktrail.Wallet.FEE_STRATEGY_MIN_RELAY_FEE, false, {allowZeroConfSelf: false}).then(function(txId) { |
|
53
|
|
|
console.log(txId); |
|
|
|
|
|
|
54
|
|
|
}); |
|
55
|
|
|
}; |
|
56
|
|
|
|
|
57
|
|
|
// start at 20 BTC, * 0.5 every time we can't send such a large amount anymore |
|
58
|
|
|
var value = 20 * ONEBTC; |
|
59
|
|
|
// track retries |
|
60
|
|
|
var retries = 0; |
|
61
|
|
|
|
|
62
|
|
|
var keepSpending = function() { |
|
63
|
|
|
return wallet.getBalance().then(function(b) { |
|
64
|
|
|
console.log(b); |
|
|
|
|
|
|
65
|
|
|
|
|
66
|
|
|
// do a split send |
|
67
|
|
|
return splitSend(Math.min(b[0], value)) |
|
68
|
|
|
.then(function() { |
|
69
|
|
|
// keep sending for as long as possible |
|
70
|
|
|
return keepSpending() |
|
71
|
|
|
.then(function() { |
|
72
|
|
|
// reset retries on success |
|
73
|
|
|
retries = 0; |
|
74
|
|
|
}); |
|
75
|
|
|
}, function(e) { |
|
76
|
|
|
console.error(e.message || e); |
|
77
|
|
|
|
|
78
|
|
|
// if TX is too big (or MrSign times out cuz TX is too big to sign) |
|
79
|
|
|
if (e.message.match(/too big/) || e.message.match(/MrSign/)) { |
|
80
|
|
|
// if value reaches <= MINVALUE then we're done(ish) |
|
81
|
|
|
if (value <= MINVALUE) { |
|
82
|
|
|
retries++; |
|
83
|
|
|
|
|
84
|
|
|
// retry 3 more times, otherwise done |
|
85
|
|
|
if (retries >= 3) { |
|
86
|
|
|
throw new Error("DONE"); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
// keep trying |
|
90
|
|
|
return keepSpending(); |
|
91
|
|
|
} else { |
|
92
|
|
|
// halve the value and try again |
|
93
|
|
|
value *= 0.5; |
|
94
|
|
|
console.log('too big, new value:', blocktrail.toBTC(value)); |
|
|
|
|
|
|
95
|
|
|
|
|
96
|
|
|
return keepSpending(); |
|
97
|
|
|
} |
|
98
|
|
|
} else if (e.message.match(/too low/)) { |
|
99
|
|
|
// halve the value and try again |
|
100
|
|
|
value *= 0.5; |
|
101
|
|
|
console.log('too big, new value:', blocktrail.toBTC(value)); |
|
102
|
|
|
|
|
103
|
|
|
return keepSpending(); |
|
104
|
|
|
} else if (e.message.match(/All usable unspent/)) { |
|
105
|
|
|
// halve the value and try again, but with a timeout |
|
106
|
|
|
value *= 0.5; |
|
107
|
|
|
console.log('too big, new value:', blocktrail.toBTC(value)); |
|
108
|
|
|
|
|
109
|
|
|
var deferred = q.defer(); |
|
110
|
|
|
|
|
111
|
|
|
setTimeout(function() { |
|
112
|
|
|
deferred.resolve(); |
|
113
|
|
|
}, 11000); |
|
114
|
|
|
|
|
115
|
|
|
return deferred.promise.then(function() { |
|
116
|
|
|
return keepSpending(); |
|
117
|
|
|
}); |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
throw e; |
|
121
|
|
|
}); |
|
122
|
|
|
}); |
|
123
|
|
|
}; |
|
124
|
|
|
|
|
125
|
|
|
return keepSpending(); |
|
126
|
|
|
}); |
|
127
|
|
|
}) |
|
128
|
|
|
.catch(function(e) { |
|
129
|
|
|
console.error(e); |
|
130
|
|
|
}); |
|
131
|
|
|
|